package com.shanjupay.transaction.service;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.shanjupay.common.cache.Cache;
import com.shanjupay.common.domain.BusinessException;
import com.shanjupay.common.domain.CommonErrorCode;
import com.shanjupay.common.util.RedisUtil;
import com.shanjupay.transaction.api.PayChannelService;
import com.shanjupay.transaction.api.dto.PayChannelDTO;
import com.shanjupay.transaction.api.dto.PayChannelParamDTO;
import com.shanjupay.transaction.api.dto.PlatformChannelDTO;
import com.shanjupay.transaction.convert.PayChannelParamConvert;
import com.shanjupay.transaction.convert.PlatformChannelConvert;
import com.shanjupay.transaction.entity.AppPlatformChannel;
import com.shanjupay.transaction.entity.PayChannelParam;
import com.shanjupay.transaction.entity.PlatformChannel;
import com.shanjupay.transaction.mapper.AppPlatformChannelMapper;
import com.shanjupay.transaction.mapper.PayChannelParamMapper;
import com.shanjupay.transaction.mapper.PlatformChannelMapper;
import org.apache.dubbo.config.annotation.Service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * @program: shanjupay
 * @description:
 * @author: Mr.Hkc
 * @create: 2020-08-19 14:29
 **/
@Service
public class PayChannelServiceImpl implements PayChannelService {


    @Autowired
    PlatformChannelMapper platformChannelMapper;

    @Autowired
    AppPlatformChannelMapper appPlatformChannelMapper;

    @Autowired
    PayChannelParamMapper payChannelParamMapper;

    @Autowired
    Cache cache;


    /**
     *获取指定应用指定服务类型下所包含的某个原始支付参数
     * @param appId
     * @param platformChannel
     * @param payChannel
     * @return
     */
    public PayChannelParamDTO queryParamByAppPlatformAndPayChannel(String appId, String platformChannel, String payChannel) {
        //根据应用类型和服务类型查询支付渠道参数列表
        List<PayChannelParamDTO> payChannelParamDTOS = queryPayChannelParamByAppAndPlatform(appId, platformChannel);
        for (PayChannelParamDTO payChannelParamDTO : payChannelParamDTOS) {
            if (payChannelParamDTO.getPayChannel().equals(payChannel)){
                return payChannelParamDTO;
            }
        }
        return null;
    }

    /**
     * @param appId 应用id
     * @param platformChannel 服务类型code
     * @return
     */
    public List<PayChannelParamDTO> queryPayChannelParamByAppAndPlatform(String appId, String platformChannel) {

        //先从Redis查询,如果查询到则返回,否则从数据库查询,再保存到Redis
        String redisKey = RedisUtil.keyBuilder(appId, platformChannel);
        Boolean exists = cache.exists(redisKey);
        if (exists){
            //从redis获取支付渠道参数列表(json串)
            String PayChannelParamDTO_String = cache.get(redisKey);
            //将json串转为List<PayChannelParamDTO>
            List<PayChannelParamDTO> payChannelParamDTOS = JSON.parseArray(PayChannelParamDTO_String, PayChannelParamDTO.class);
            return payChannelParamDTOS;
        }

        //根据应用和服务类型找到绑定id
        Long appPlatformChannelId = selectIdByAppPlatformChannel(appId, platformChannel);
        if (appPlatformChannelId == null){
            return null;
        }
        //应用和服务类型绑定id查询支付渠道参数记录
        List<PayChannelParam> payChannelParams = payChannelParamMapper.selectList(new LambdaQueryWrapper<PayChannelParam>().eq(PayChannelParam::getAppPlatformChannelId, appPlatformChannelId));
        List<PayChannelParamDTO> payChannelParamDTOS = PayChannelParamConvert.INSTANCE.listentity2listdto(payChannelParams);

        //向Redis缓存支付渠道参数
        updateCache(appId,platformChannel);
        return payChannelParamDTOS;
    }


    /**
     * 支付渠道参数配置
     * @param payChannelParam 配置支付渠道参数 包括:应用id 服务类型 支付渠道 配置名称 配置参数
     * @throws BusinessException
     */
    public void savePayChannelParam(PayChannelParamDTO payChannelParam) throws BusinessException {

        if (payChannelParam == null || payChannelParam.getChannelName() == null || payChannelParam.getParam() == null){
            throw new BusinessException(CommonErrorCode.E_300009);
        }

        //1.根据应用  服务类型  支付渠道查询一条记录
        //1.1根据应用 服务类型查询应用与服务类型的绑定id
        Long appPlatformChannelId = selectIdByAppPlatformChannel(payChannelParam.getAppId(), payChannelParam.getPlatformChannelCode());
        if (appPlatformChannelId == null){
            throw new BusinessException(CommonErrorCode.E_300010);
        }

        //1.2根据应用与服务类型的绑定id和支付渠道查询PayChannelParam的一条记录
        PayChannelParam entity = payChannelParamMapper.selectOne(new LambdaQueryWrapper<PayChannelParam>()
                .eq(PayChannelParam::getAppPlatformChannelId, appPlatformChannelId)
                .eq(PayChannelParam::getPayChannel, payChannelParam.getPayChannel()));
        //如果存在配置则执行更新
        if (entity != null){
            entity.setChannelName(payChannelParam.getChannelName());
            entity.setParam(payChannelParam.getParam());
            payChannelParamMapper.updateById(entity);
        }else {
            //否则执行添加
            PayChannelParam entityNew = PayChannelParamConvert.INSTANCE.dto2entity(payChannelParam);
            entityNew.setId(null); //避免mybatis-plus生成主键id  将id置空
            entityNew.setAppPlatformChannelId(appPlatformChannelId); //应用与服务绑定的关系id
            payChannelParamMapper.insert(entityNew);
        }
        //向Redis缓存支付渠道参数
        updateCache(payChannelParam.getAppId(), payChannelParam.getPlatformChannelCode());

    }

    /**
     * @return
     * @throws BusinessException
     */
    public List<PlatformChannelDTO> queryPlatformChannel() throws BusinessException {
        //查询platform_channel表的全部记录
        List<PlatformChannel> platformChannels = platformChannelMapper.selectList(null);
        //将platformChannels的entityList转为dto的list
        return PlatformChannelConvert.INSTANCE.listentity2listdto(platformChannels);
    }

    /**
     * 为app绑定平台服务类型
     *
     * @param appId                应用id
     * @param platformChannelCodes 服务类型的code
     * @throws BusinessException
     */
    @Transactional
    public void bindPlatformChannelForApp(String appId, String platformChannelCodes) throws BusinessException {
        //1.根据应用id和服务类型code查询,如果已经绑定ze则不再插入,否则插入记录
        AppPlatformChannel appPlatformChannel = appPlatformChannelMapper.selectOne(new LambdaQueryWrapper<AppPlatformChannel>()
                .eq(AppPlatformChannel::getAppId, appId)
                .eq(AppPlatformChannel::getPlatformChannel, platformChannelCodes));
        if (appPlatformChannel == null) {
            //向app_platform_channel插入记录
            AppPlatformChannel entity = new AppPlatformChannel();
            entity.setAppId(appId); //应用id
            entity.setPlatformChannel(platformChannelCodes); //服务类型
            appPlatformChannelMapper.insert(entity);
        }

    }

    /**
     * 应用是否已经绑定了某个类型的服务
     *
     * @param appId           应用id
     * @param platformChannel 服务类型
     * @return 已绑定返回1，否则 返回0
     * @throws BusinessException
     */
    public int queryAppBindPlatformChannel(String appId, String platformChannel) throws BusinessException {
        int count = appPlatformChannelMapper.selectCount(new LambdaQueryWrapper<AppPlatformChannel>()
                .eq(AppPlatformChannel::getAppId, appId)
                .eq(AppPlatformChannel::getPlatformChannel, platformChannel));
        return count > 0 ? 1 : 0;
    }

    /**
     * 根据服务类型查询支付渠道
     * @param platformChannelCode 服务类型代码
     * @return
     * @throws BusinessException
     */
    public List<PayChannelDTO> queryPayChannelByPlatformChannel(String platformChannelCode) throws BusinessException {
        return platformChannelMapper.selectPayChannelByPlatformChannel(platformChannelCode);
    }


    /**
     * 根据appid和服务类型查询应用与服务类型绑定id
     * @param appId
     * @param platformChannelCode
     * @return
     */
    private Long selectIdByAppPlatformChannel(String appId,String platformChannelCode){
        AppPlatformChannel appPlatformChannel = appPlatformChannelMapper.selectOne(new LambdaQueryWrapper<AppPlatformChannel>()
                .eq(AppPlatformChannel::getAppId, appId)
                .eq(AppPlatformChannel::getPlatformChannel, platformChannelCode));
        if (appPlatformChannel != null){
            return appPlatformChannel.getId();
        }
        return null;
    }

    /**
     * 根据应用和服务类型将查询到的支付渠道参数配置列表写入redis
     * @param appId 应用id
     * @param platformChannelCode 服务类型code
     */
    private void updateCache(String appId,String platformChannelCode){

        //得到Redis中key(支付渠道参数列表的key)
        //格式:SJ_PAY_PARAM:应用id:服务类型code,例如:SJ_PAY_PARAM:b910da455bc84514b324656e1088320b:shanju_c2b
        String redisKey = RedisUtil.keyBuilder(appId, platformChannelCode);
        Boolean exists = cache.exists(redisKey);
        //根据key查询redis  如果缓存中存在,则将redisKey删除,再查询 -->保证Redis数据的完整性
        if (exists){
            cache.del(redisKey);
        }
        //根据应用id和服务类型code查询支付渠道参数列表
        //根据应用和服务类型找到他们绑定id
        Long appPlatformChannelId = selectIdByAppPlatformChannel(appId, platformChannelCode);
        if (appPlatformChannelId != null){
            //应用和服务类型绑定id查询支付渠道参数记录
            List<PayChannelParam> payChannelParams = payChannelParamMapper.selectList(new LambdaQueryWrapper<PayChannelParam>().eq(PayChannelParam::getAppPlatformChannelId, appPlatformChannelId));
            List<PayChannelParamDTO> payChannelParamDTOS = PayChannelParamConvert.INSTANCE.listentity2listdto(payChannelParams);
            cache.set(redisKey, JSON.toJSON(payChannelParamDTOS).toString());
        }

    }



}

